﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Windows.Forms;
using WinApi;
using static WenSkin.Controls.WenListViewItem;

namespace WenSkin.Controls
{
    [ToolboxBitmap(typeof(ListView))]
    public partial class WenListView : ListView
    {
        public WenListView()
        {
            this.View = View.Details;
            this.FullRowSelect = true;

            base.SetStyle(
                 //ControlStyles.UserPaint |
                 ControlStyles.DoubleBuffer |
                 ControlStyles.OptimizedDoubleBuffer |
                 ControlStyles.AllPaintingInWmPaint |
                 ControlStyles.ResizeRedraw |
                 ControlStyles.SupportsTransparentBackColor, true);
            base.UpdateStyles();
            OwnerDraw = true;
            this.BackColor = Color.FromArgb(37, 37, 38);
            this.BorderStyle = BorderStyle.FixedSingle;
            itemlistInstance();
            this.ForeColor = Color.White;
        }

        #region 私有属性

        private int itemHeight = 30;
        private Size itemIconSize = new Size(30, 30);
        private WenListViewColumnHeaderCollection columns;

        private WenListViewItemCollection items;

        #endregion

        #region 公有属性

        [Category("Wen"), Description("当imagelist无值 默认图标"), DefaultValue(null)]
        public Image ItemIcon { get; set; }

        [Category("Wen"), Description("没有图标情况，项高度"), DefaultValue(30)]
        public int ItemHeight
        {
            get => itemHeight;
            set
            {
                itemHeight = value;
                itemIconSize = new Size(value, value);
                itemlistInstance();
                this.Invalidate();
            }
        }

        public Color HeadColor { get; set; }
        #endregion

        #region 重写属性

        [Category("Wen"), Description("是否显示复选框"), DefaultValue(false)]
        public new bool CheckBoxes { get => base.CheckBoxes; set => base.CheckBoxes = value; }
        public new ImageList SmallImageList { get; set; }

        [Category("Wen"), Description("项集合")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public new WenListViewItemCollection Items => items ?? (items = new WenListViewItemCollection(this));

        [Category("Wen"), Description("列集合")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        [Editor(typeof(Design.Editor.WenCollectionEditor), typeof(System.Drawing.Design.UITypeEditor))]
        public new WenListViewColumnHeaderCollection Columns => columns ?? (columns = new WenListViewColumnHeaderCollection(this));
        #endregion

        #region 委托

        public delegate void WenListViewItemEventHandler(object sender, WenListViewItemEventArgs e);
        public class WenListViewItemEventArgs: EventArgs
        {
            public WenListViewItemEventArgs(WenListViewItem wenListViewItem)
            {
                WenListViewItem = wenListViewItem;
            }

            public WenListViewItem WenListViewItem { get; set; }
        }

        [Category("Wen"), Description("Item 项鼠标点击事件")]
        public event WenListViewItemEventHandler WenListViewItemClick;

        #endregion

        #region 绑定数据


        private object dataSource { get; set; }
        [Browsable(false)]
        public object DataSource
        {
            get => dataSource;
            set
            {
                if (value != null)
                {
                    dataSource = value;
                    DataBind();
                }
            }
        }
        private void DataBind()
        {
            if (dataSource == null)
                return;
            this.Items.Clear();

            switch (dataSource)
            {
                case DataSet ds:
                    DataBind(ds.Tables[0]);
                    break;
                case DataTable dt:
                    DataBind(dt);
                    break;
                case IList ilist:
                    {
                        foreach (var li in ilist)
                        {
                            WenListViewItem item = new WenListViewItem(this)
                            {
                                Tag = ilist,
                                ImageIndex = 0
                            };
                            foreach (WenColumnHeader cl in Columns)
                            {    
                                List<System.Reflection.PropertyInfo> propertyInfos = new List<System.Reflection.PropertyInfo>(li.GetType().GetProperties());
                                string value = propertyInfos
                                    .Find(a => a.Name.ToUpper() == cl.CloumnName.ToUpper())?.GetValue(li, null)?.ToString();

                                item.Cells.Add(cl.CloumnName, value);

                                if (Columns.IndexOf(cl) == 0)
                                    item.Text = value;
                                else
                                    item.SubItems.Add(value);
                            }
                            Items.Add(item);
                        }
                        break;
                    }
            }
            //绑定DataTable 数据
            void DataBind(DataTable dt)
            {
                foreach (DataRow dr in dt.Rows)
                {
                    WenListViewItem item = new WenListViewItem(this)
                    {
                        Tag = dr,
                        ImageIndex = 0
                    };
                    foreach (WenColumnHeader cl in Columns)
                    {
                        string value = dr[cl.CloumnName]?.ToString();
                        item.Cells.Add(cl.CloumnName,value);

                        if (Columns.IndexOf(cl) == 0)
                            item.Text = value;
                        else
                            item.SubItems.Add(value);
                    }
                    Items.Add(item);
                }
            }
        }

        private ImageList itemlistInstance()
        {
            ImageList imageList = new ImageList() { ImageSize = itemIconSize };
            if (ItemIcon != null)
                imageList.Images.Add(ItemIcon);
            else
                imageList.Images.Add(Properties.Resources.itemImage);
            base.SmallImageList = imageList;
            return imageList;
        }

        #endregion

        #region 重绘项目

        protected override void OnDrawColumnHeader(DrawListViewColumnHeaderEventArgs e)
        {
            Graphics g = e.Graphics;
            g.SetGDIHigh();
            Rectangle rec = e.Bounds;

            using Brush b = new SolidBrush(Color.FromArgb(45, 45, 48));
            using Brush bstr = new SolidBrush(Color.FromArgb(199, 199, 199));
            using Pen p = new Pen(Color.FromArgb(199, 199, 199));

            //画背景
            g.FillRectangle(b, new Rectangle(rec.X , rec.Y, rec.Width, rec.Height - 1));
            //画分割线
            g.DrawLine(p, rec.X + rec.Width-1, rec.Y, rec.X + rec.Width-1, rec.Y + rec.Height);
            //画文字
            g.DrawString(e.Header.Text, this.Font, bstr, rec, ControlHelper.StringConters);
        }
        protected override void OnDrawItem(DrawListViewItemEventArgs e)
        {
            Graphics g = e.Graphics;
            g.ResetClip();
            g.SetGDIHigh();

            Rectangle rec = new Rectangle(0, e.Bounds.Y, this.Width, e.Bounds.Height);
            using Pen pen = new Pen(Color.FromArgb(70, 70, 70));
            g.DrawLine(pen, 0, rec.Y + rec.Height - 1, rec.Width, rec.Y + rec.Height - 1);
        }
        protected override void OnDrawSubItem(DrawListViewSubItemEventArgs e)
        {
            if (e.Item.ImageIndex < 0)
            {
                e.Item.ImageIndex = 0;
            }

            Graphics g = e.Graphics;
            g.SetGDIHigh();
            Rectangle rec = new Rectangle(e.Bounds.X, e.Bounds.Y, e.Bounds.Width+1, e.Bounds.Height);
            Rectangle recStr = rec;

            g.SetClip(new Rectangle(rec.X, rec.Y+1, rec.Width, rec.Height - 3));
            //当为最后一列数据时事件
            if (e.ColumnIndex + 1 == this.Columns.Count)
            {
                g.SetClip(new Rectangle(rec.X, rec.Y + 1, rec.Width - 1, rec.Height - 3));
            }

            using Brush bSelected = new SolidBrush(Color.FromArgb(63, 63, 70));
            using Brush bNone = new SolidBrush(Color.FromArgb(37,37,38));

            DrawBackdrop(g, rec);


            //画背景
            void DrawBackdrop(Graphics g,Rectangle rec)
            {
                if (e.Item.Selected)
                    g.FillRectangle(bSelected, rec);//选中
                else
                    g.FillRectangle(bNone, rec);//普通
            }

            //判定为第一列，画图标
            using Brush brush = new SolidBrush(this.ForeColor);

            Image image = e.Item.ImageList.Images[e.Item.ImageIndex];

            //获取文字宽度
            if (e.ColumnIndex == 0)
            {
                int indexWidth = TextRenderer.MeasureText((e.ItemIndex + 1).ToString(), e.Item.Font).Width + 2;
                Rectangle recItemLine = new Rectangle(rec.X, rec.Y, indexWidth, rec.Height);
                Rectangle recImage = new Rectangle(rec.X + indexWidth + 3,
                                                   rec.Y + (rec.Height - image.Height / 2) / 2,
                                                   image.Width / 2,
                                                   image.Height / 2);
                //重置绘制文字区域
                recStr = new Rectangle(recImage.X + recImage.Width + 3,
                                       rec.Y,
                                       rec.Width - recItemLine.Width - recImage.Width,
                                       rec.Height);
                if (this.CheckBoxes)
                {
                    int checkWidth = 15;
                    recItemLine.Offset(checkWidth, 0);
                    recImage.Offset(checkWidth, 0);
                    recStr.Offset(checkWidth, 0);

                    int checkY = (rec.Height - checkWidth) / 2 + rec.Y;

                    if (e.Item.Checked)
                    {
                        CheckBoxRenderer.DrawCheckBox(g,
                                                      new Point(rec.X, checkY),
                                                      System.Windows.Forms.VisualStyles.CheckBoxState.CheckedNormal);
                    }
                    else
                    {
                        CheckBoxRenderer.DrawCheckBox(g,
                                                      new Point(rec.X, checkY),
                                                      System.Windows.Forms.VisualStyles.CheckBoxState.UncheckedNormal);
                    }
                }
                g.DrawImage(image, recImage);
                g.DrawString((e.ItemIndex + 1).ToString(), e.Item.Font, brush, recItemLine, ControlHelper.StringConters);
            }
            g.DrawString(e.SubItem.Text, e.Item.Font, brush, recStr, ControlHelper.StringConters);
        }      

        #endregion

        #region 项点击事件
        protected override void OnMouseClick(MouseEventArgs e)
        {
            base.OnMouseClick(e);
            if(GetItemAt(e.X, e.Y) is WenListViewItem item)
            {
                WenListViewItemClick?.Invoke(this, new WenListViewItemEventArgs(item));
            }
        }

        #endregion

        #region 空白区域美化

        protected override void CreateHandle()
        {
            base.CreateHandle();
            if (headerNativeWindow == null)
            {
                headerNativeWindow = new HeaderNativeWindow(this);
            }
        }

        protected override void DestroyHandle()
        {
            base.DestroyHandle();
            if (headerNativeWindow != null)
            {
                headerNativeWindow = null;
            }
        }

        IntPtr headerWnd => WindowsAPI.FindWindowEx(this.Handle, IntPtr.Zero, "SysHeader32", null);

        private Rectangle HeaderEndRect()
        {
            RECT rect = new RECT();
            RECT rect2 = new RECT();
            WindowsAPI.SendMessage(headerWnd, 0x1207, Columns.Count - 1, ref rect);
            WindowsAPI.GetWindowRect(headerWnd, ref rect2);
            return new Rectangle(rect.X + rect.Width , rect.Y, this.Width - (rect.X + rect.Width), rect.Height);
        }

        HeaderNativeWindow headerNativeWindow;
        private class HeaderNativeWindow : NativeWindow
        {
            public WenListView owner;
            IntPtr header;
            public HeaderNativeWindow(WenListView owner)
            {
                this.owner = owner;
                header = owner.headerWnd;
                base.AssignHandle(header);
            }
            protected override void WndProc(ref Message m)
            {
                base.WndProc(ref m);
                if (m.Msg == 0xF || m.Msg == 0x47)
                {
                    IntPtr hdc = WindowsAPI.GetDC(m.HWnd);
                    try
                    {
                        using Graphics g = Graphics.FromHdc(hdc);
                        Rectangle rec = owner.HeaderEndRect();
                        owner.ReHeader(g, rec);
                    }
                    finally
                    {
                        WindowsAPI.ReleaseDC(m.HWnd, hdc);
                    }
                }
            }
        }
        private void ReHeader(Graphics g, Rectangle rec)
        {
            g.FillRectangle(new SolidBrush(Color.FromArgb(45, 45, 48)), rec);
        }
        #endregion

        public class WenListViewColumnHeaderCollection : ColumnHeaderCollection
        {
            private readonly WenListView owner;
            public WenListViewColumnHeaderCollection(WenListView owner) : base(owner)
            {
                this.owner = owner;
            }

            public new WenColumnHeader this[int index] => base[index] as WenColumnHeader;
            public new WenColumnHeader this[string key]
            {
                get
                {
                    foreach (WenColumnHeader item in this)
                    {
                        if (item.Text.ToUpper() == key.ToUpper())
                        {
                            return item;
                        }
                    }
                    return null;
                }
            }


            public void Add(WenColumnHeader value)
            {
                base.Add(value);
            }

            public void AddRange(WenColumnHeader[] values)
            {
                base.AddRange(values);
            }
        }
        public class WenListViewItemCollection : ListViewItemCollection
        {
            public WenListViewItemCollection(WenListView owner) : base(owner)
            {
            }

            public new WenListViewItem this[int index] => (base[index] is WenListViewItem item) ? item : null;
            public void Add(WenListViewItem value)
            {
                base.Add(value);
            }
        }

    }
}
